<template>
  <view class="mxp-switch" :class="[disabled || isLoading ? 'disabled' : '', cusClass]" :style="[switchStyle, cusStyle]" @click="clickHandler">
    <view class="circle-view" :style="[circleViewStyle]">
      <view :style="{ transform: 'scale(0.55)' }">
        <mxp-icon v-if="isLoading" :spin="true" name="jiazai" :color="iconColor" :size="size"></mxp-icon>
        <slot v-else-if="isActive" name="activeIcon"></slot>
        <slot v-else-if="!isActive" name="inactiveIcon"></slot>
      </view>
    </view>
  </view>
</template>

<script lang="ts" setup>
  import { type CSSProperties, type PropType, computed, shallowReactive, watch } from 'vue';
  import MxpIcon from '../mxp-icon/mxp-icon.vue';
  import { publicStyeProps } from '../mxp-tool/utils/public-props';
  import type { $AllColorStr, $SizeUnitStr } from '@/mxp-ui/mxp-tool/types/interface';
  import { defThemeColor } from '../mxp-tool/theme/theme';
  import { lightenDarkenColorStorage } from '../mxp-tool/utils/color';

  defineOptions({
    name: 'mxp-switch',
  });

  const props = defineProps({
    /** 绑定的值 */
    modelValue: { type: [Boolean, String, Number], default: false },
    /** 是否为加载中状态 (尽量不要穿) */
    loading: { type: Boolean, default: false },
    /** 是否为禁用状态 */
    disabled: { type: Boolean, default: false },
    /** 开关大小 */
    size: { type: String as PropType<$SizeUnitStr>, default: '20px' },
    /** 整个按钮 ‘开’ 状态下的背景 */
    activeColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /**整个按钮 ‘关’ 状态下的背景 */
    inactiveColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 圆圈 ‘开’ 状态下的背景 */
    circleActiveColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 圆圈 ‘开’ 状态下的背景 */
    circleInactiveColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 加载菊花 ‘开’ 状态下的背景 */
    iconActiveColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 加载菊花 ‘开’ 状态下的背景 */
    iconInactiveColor: { type: String as PropType<$AllColorStr>, default: undefined },
    /** 自定义 ‘开’ 状态下绑定的值 */
    activeValue: { type: [Boolean, String, Number], default: true },
    /** 自定义 ‘关’ 状态下绑定的值 */
    inactiveValue: { type: [Boolean, String, Number], default: false },
    /** 开关状态改变前执行的函数(需要返回 true 或者 false) */
    beforeChange: { type: Function as PropType<() => Promise<boolean> | boolean>, default: undefined },
    ...publicStyeProps,
  });
  defineSlots<{
    /** 自定义 选中图标 */
    activeIcon: () => void;
    /** 自定义未选中图标 */
    inactiveIcon: () => void;
  }>();
  const emits = defineEmits<{
    (e: 'change', data: boolean | number | string): void;
    (e: 'update:modelValue', data: boolean | number | string): void;
  }>();

  const data = shallowReactive({
    interiorLoading: false,
    innerValue: props.modelValue,
  });

  /** 是否选中 */
  const isActive = computed(() => data.innerValue === props.activeValue);

  /** 是否 加载中 */
  const isLoading = computed(() => data.interiorLoading || props.loading);

  const newActiveColor = computed(() => props.activeColor || defThemeColor.value.primary);
  const newInactiveColor = computed(() => props.inactiveColor || defThemeColor.value.fill3);
  const iconColor = computed(() =>
    isActive.value
      ? ((props.iconActiveColor || lightenDarkenColorStorage(newActiveColor.value, 0.7) || defThemeColor.value.fill3) as $AllColorStr)
      : ((props.iconInactiveColor || lightenDarkenColorStorage(newInactiveColor.value, 0.7) || defThemeColor.value.fill3) as $AllColorStr)
  );

  const switchStyle = computed<CSSProperties>(() => {
    const style: CSSProperties = {};

    style['--width'] = `calc(${props.size} * 2 + 4px)`;
    style['--height'] = `calc(${props.size} + 4px)`;
    style['--background'] = isActive.value ? newActiveColor.value : newInactiveColor.value;
    return style;
  });

  const circleViewStyle = computed<CSSProperties>(() => {
    const style: CSSProperties = {};
    style.width = props.size;
    style.height = props.size;
    style.height = props.size;
    const translateX = isActive.value ? '-2px' : `calc(-${props.size} - 2px)`;
    style.background = isActive.value ? props.circleActiveColor || defThemeColor.value.fill : props.circleInactiveColor || defThemeColor.value.fill;
    style.transform = `translateX(${translateX})`;
    style.boxShadow = `1px 1px 1px 0 rgba(0, 0, 0, 0.25)`;

    return style;
  });

  watch(
    () => props.modelValue,
    (newVal) => {
      data.innerValue = newVal;
    },
    { immediate: true }
  );

  /**
   * 点击事件
   */
  async function clickHandler() {
    if (!props.disabled && !isLoading.value) {
      let value = isActive.value ? props.inactiveValue : props.activeValue;
      if (typeof props.beforeChange === 'function') {
        try {
          data.interiorLoading = true;
          const state = await props.beforeChange();
          value = state ? props.activeValue : props.inactiveValue;
        } catch (error) {}
        data.interiorLoading = false;
      }
      emits('update:modelValue', value);
      emits('change', value);
    }
  }
</script>

<style lang="scss" scoped>
  .mxp-switch {
    position: relative;
    display: flex;
    flex-flow: row nowrap;
    align-items: center;
    justify-content: flex-end;
    width: var(--width);
    height: var(--height);
    overflow: hidden;
    background: var(--background);
    border-radius: 100px;
    transition-timing-function: ease-in-out;
    transition-duration: 0.4s;
    transition-property: background;

    &.disabled {
      opacity: 0.6;
    }

    .circle-view {
      display: flex;
      flex-flow: row nowrap;
      align-items: center;
      justify-content: center;
      border-radius: 100px;
      transition-timing-function: ease-in-out;
      transition-duration: 0.4s;
      transition-property: transform, background;
    }
  }
</style>
